package cn.edu.cug.cs.gtl.docsrv.shp.catalog;

import cn.edu.cug.cs.gtl.mybatis.mapper.shp.ShpCatalog;
import cn.edu.cug.cs.gtl.mybatis.mapper.txt.TxtCatalog;
import cn.edu.cug.cs.gtl.protos.Tree;
import cn.edu.cug.cs.gtl.protos.TreeNode;
import cn.edu.cug.cs.gtl.tree.HashTree;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 将List<ShpCatalog>转成目录树；
 * HashTree主要供后端程序内部使用
 * Tree主要供前端或交换数据时候使用。
 */
public class CatalogTree {
    private String rootName = "root";
    private List<ShpCatalog> shpCatalogs = null;
    HashTree hashTree = null;
    public CatalogTree(List<ShpCatalog> shpCatalogs){
        this.shpCatalogs=shpCatalogs;
        hashTree = createHashTree();
    }
    public CatalogTree(List<ShpCatalog> shpCatalogs, String rootName){
        this.shpCatalogs=shpCatalogs;
        this.rootName = rootName;
        hashTree = createHashTree();
    }

    /**
     * 返回构建的HashTree
     * @return HashTree
     */
    public HashTree getHashTree(){
        if (this.hashTree==null)
            this.hashTree = createHashTree();
        return this.hashTree;
    }

    /**
     * 构建分类目录树HashTree
     * @return 返回构建的HashTree
     */
    private HashTree createHashTree(){
        try {
            if(shpCatalogs==null)  return null;
            HashTree hashTree = new HashTree();
            HashTree root = hashTree;
            for(ShpCatalog shpCatalog: shpCatalogs){
                if(shpCatalog.getCatalogName().contains("/")){
                    String [] ss = shpCatalog.getCatalogName().split("/");
                    for(int i=0;i<ss.length-1;++i){
                        ShpCatalog shpCatalogRoot = new ShpCatalog();
                        shpCatalogRoot.setCatalogInternalId(BigDecimal.valueOf(-1L));
                        shpCatalogRoot.setCatalogName(ss[i]);
                        shpCatalogRoot.setCatalogOrder(shpCatalog.getCatalogOrder());
                        hashTree = hashTree.add(shpCatalogRoot);
                    }
                    ShpCatalog shpCatalog1= new ShpCatalog();
                    shpCatalog1.setCatalogInternalId(shpCatalog.getCatalogInternalId());
                    shpCatalog1.setCatalogName(ss[ss.length-1]);
                    shpCatalog1.setCatalogOrder(shpCatalog.getCatalogOrder());
                    hashTree = hashTree.add(shpCatalog1);
                }
                else{
                    hashTree = hashTree.add(shpCatalog);
                }
                hashTree=root;
            }
            //合并树种兄弟节点名称相同的项
            mergeNodes(root);
            return root;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 同一层中节点ShpCatalog同名合并
     * @param hashTree
     */
    private void mergeNodes(HashTree hashTree){
        if(hashTree==null || hashTree.isEmpty())
            return;
        //处理子树合并
        Set<Object> set = hashTree.keySet();
        int c = set.size();
        if(c<2) return;

        Object [] a = set.toArray();
        for(int i=0;i<c-1;++i){
            for(int j=i+1;j<c;++j){

                ShpCatalog shpCatalog_i = ((ShpCatalog)(a[i]));
                ShpCatalog shpCatalog_j = ((ShpCatalog)(a[j]));
                boolean b = shpCatalog_i.getCatalogName().equals(shpCatalog_j.getCatalogName());
                if(b){//合并
                    HashTree hashTree_i = hashTree.get(shpCatalog_i);
                    HashTree hashTree_j = hashTree.get(shpCatalog_j);
                    long catalogId_i = shpCatalog_i.getCatalogInternalId().longValue();
                    long catalogId_j = shpCatalog_j.getCatalogInternalId().longValue();

                    if(catalogId_i>=catalogId_j){
                        //将j合并到i中，并将j删除
                        if(hashTree_i==null || hashTree_i.isEmpty())
                            hashTree.put(shpCatalog_i,hashTree_j);
                        else{
                            if(hashTree_j!=null && !hashTree_j.isEmpty())
                                hashTree_i.putAll(hashTree_j);
                        }
                        hashTree.remove(shpCatalog_j);
                        a = hashTree.keySet().toArray();
                        c--;
                        j--;
                    }
                    else{
                        //将i合并到j中，并将i删除
                        if(hashTree_j==null || hashTree_j.isEmpty())
                            hashTree.put(shpCatalog_j,hashTree_i);
                        else{
                            if(hashTree_i!=null && !hashTree_i.isEmpty())
                                hashTree_j.putAll(hashTree_i);
                        }
                        hashTree.remove(shpCatalog_i);
                        a = hashTree.keySet().toArray();
                        c--;
                        if(i>0) i--;
                        j--;
                    }

                }
            }
        }
        //合并后的树的子树处理
        Object [] objects = hashTree.keySet().toArray();
        if(objects==null || objects.length==0) return;
        for(Object o : objects){
            HashTree sub = hashTree.get(o);
            mergeNodes(sub);
        }
    }

    /**
     * 将CatalogTree转换成通用Tree
     * @return
     */
    public Tree cloneTree(){
        TreeNode.Builder b = TreeNode.newBuilder();
        b = cloneNode(hashTree,b);
        b.setIdentifier(-1L);
        b.setName(this.rootName);
        return Tree.newBuilder().setRoot(b.build()).build();
    }


    /**
     * 将HashTree转换成通用Tree，主要供前后端交换
     * @param hashTree
     * @param tnb
     * @return
     */
    private TreeNode.Builder cloneNode(HashTree hashTree,TreeNode.Builder tnb){
        if(hashTree==null) return null;
        if(hashTree.isEmpty()) return null;
        Set<Map.Entry<Object,HashTree>> set = hashTree.entrySet();
        for(Map.Entry<Object,HashTree> p : set){
            TreeNode.Builder tnbSub = TreeNode.newBuilder();
            ShpCatalog shpCatalog = (ShpCatalog) p.getKey();
            tnbSub.setIdentifier(shpCatalog.getCatalogInternalId().longValue());
            tnbSub.setName(shpCatalog.getCatalogName());
            //String order = shpCatalog.getCatalogOrder();
            //if(order!=null && !order.isEmpty())
//                tnbSub.setOrder(order);
            HashTree hashTreeSub = p.getValue();
            if(hashTreeSub!=null && !hashTreeSub.isEmpty()){
                cloneNode(hashTreeSub,tnbSub);
                tnb.addChild(tnbSub.build());
            }
            else{
                tnb.addChild(tnbSub.build());
            }

        }
        return tnb;
    }
}
